﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ProgNetComponentsDx.Controls
{
    public partial class BackgroundControlMultiThread : BackgroundControlBase
    {
        private List<DelegateBackGroundInfo> _Actions = new List<DelegateBackGroundInfo>();
        private int CompletedActions;
        private object lockObject = new object();

        public BackgroundControlMultiThread()
        {
            InitializeComponent();
        }

        protected override void RunMainWorker()
        {
            backgroundWorker1.RunWorkerAsync();
            DelegateBackGroundInfo currentInfo = null;
            foreach (DelegateBackGroundInfo info in _Actions)
            {
                currentInfo = info;
                info.Start();
            }
        }

        protected override void OnDoWork()
        {
            while (CompletedActions < _Actions.Count)
            {
                Application.DoEvents();
            }
        }

        public void AddAction(Delegate Delegate, params object[] parameters)
        {
            if (!_IsRunning)
            {
                DelegateBackGroundInfo bgInfo = new DelegateBackGroundInfo(Delegate, parameters);
                bgInfo.RunWorkerCompleted += new EventHandler(bgInfo_RunWorkerCompleted);
                _Actions.Add(bgInfo);
            }
        }
        public void ClearActions()
        {
            if (!_IsRunning)
                _Actions.Clear();
        }

        private void bgInfo_RunWorkerCompleted(object sender, EventArgs e)
        {
            lock (lockObject)
            {
                CompletedActions++;
            }
        }
        public override void Start()
        {
            if (!_IsRunning)
                CompletedActions = 0;
            base.Start();
        }

        private class DelegateBackGroundInfo
        {
            private Delegate _Delegate;
            private object[] _Parameters;
            private BackgroundWorker _Worker;
            private Exception _Exception = null;

            public event EventHandler RunWorkerCompleted;

            public Delegate Delegate
            {
                get { return _Delegate; }
            }
            public object[] Parameters
            {
                get { return _Parameters; }
            }
            public bool IsBusy
            {
                get { return _Worker.IsBusy; }
            }
            public Exception Exception
            {
                get
                {
                    return _Exception;
                }
            }

            public DelegateBackGroundInfo(Delegate Delegate, object[] Parameters)
            {
                _Delegate = Delegate;
                _Parameters = Parameters;
                _Worker = new BackgroundWorker();
                _Worker.DoWork += new DoWorkEventHandler(_Worker_DoWork);
                _Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_Worker_RunWorkerCompleted);
                _Worker.WorkerSupportsCancellation = true;
            }

            public void Start()
            {
                _Worker.RunWorkerAsync();
            }
            
            public void Cancel()
            {
                _Worker.CancelAsync();
            }

            void _Worker_DoWork(object sender, DoWorkEventArgs e)
            {
                _Delegate.DynamicInvoke(_Parameters);
            }
            void _Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                if (RunWorkerCompleted != null)
                {
                    RunWorkerCompleted(this, EventArgs.Empty);
                }
            }
        }
    }
}
